package src

import (
	"encoding/json"
	"errors"
	"log"
	"next-ppt/method"
	"next-ppt/sql"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"time"

	"github.com/google/uuid"
	"gorm.io/gorm"

	"github.com/gin-gonic/gin"
)

// 定义Review结构体，它对应于JSON中的review数组元素
type Review struct {
	UID   int64    `json:"uid"`
	Main  string   `json:"main"`
	Files []string `json:"files,omitempty"` // 假设files是字符串数组，尽管在JSON中它是空的
	Time  int64    `json:"time"`            // 如果time是时间戳或日期时间，则可能需要使用time.Time类型
}

// 定义主结构体，它对应于JSON数组中的每个元素
type MainStruct struct {
	UID    int64    `json:"uid"`
	Main   string   `json:"main"`
	Files  []string `json:"files,omitempty"` // 假设files是字符串数组，尽管在JSON中它是空的
	Time   int64    `json:"time"`            // 如果time是时间戳或日期时间，则可能需要使用time.Time类型
	Review []Review `json:"review"`          // 嵌套的Review数组
}

type pptFilesLiats struct {
	Path     string `json:"path"`
	FileName string `json:"file_name"`
	Size     string `json:"size"`
	Time     int64  `json:"time"`
	Type     string `json:"type"`
}

func UploadPpt(c *gin.Context) {
	type ppt struct {
		Title       string `json:"title"`
		Instruction string `json:"instruction"`
		HomeInfo    string `json:"home_info"`
		Token       string `json:"token"`
	}
	var pptData ppt
	err := method.ParseJSON(c, &pptData)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}

	if pptData.Token == "" {
		c.JSON(200, gin.H{
			"message": "请登录",
		})
		return
	}
	if pptData.Title == "" || pptData.Instruction == "" {
		c.JSON(200, gin.H{
			"message": "请输入参数",
		})
		return
	}
	userId, err := method.GetTokenId(pptData.Token)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "token错误",
		})
		return
	}
	fileName := uuid.New().String() + ".json"
	_, err = os.Create("./pptReviews/" + fileName)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "创建文件失败",
		})
		return
	}
	data := &sql.PptList{
		User:        userId,
		Title:       pptData.Title,
		Instruction: pptData.Instruction,
		Time:        time.Now().Unix(),
		Img:         "",
		FileId:      0,
		ShowNum:     0,
		StarNum:     "",
		DownloadNum: 0,
		Review:      "./pptReviews/" + fileName,
		HomeInfo:    pptData.HomeInfo,
	}
	method.Db.Create(data)
	c.JSON(200, gin.H{
		"message": "success",
		"id":      data.ID,
	})
}

func CancelUploadPpt(c *gin.Context) {
	type ppt struct {
		PptId int64  `json:"ppt_id"`
		Token string `json:"token"`
	}
	var pptData ppt
	err := method.ParseJSON(c, &pptData)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	if pptData.Token == "" {
		c.JSON(200, gin.H{
			"message": "请登录",
		})
		return
	}
	userId, err := method.GetTokenId(pptData.Token)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "token错误",
		})
		return
	}

	var pptList sql.PptList
	method.Db.Where("id = ?", pptData.PptId).First(&pptList)
	println(pptList.User, userId)
	if userId == pptList.User {
		method.Db.Delete(&sql.PptList{}, pptData.PptId)
	} else {
		c.JSON(
			200, gin.H{
				"message": "没有权限",
			},
		)
		return
	}
	c.JSON(200, gin.H{
		"message": "success",
	})
}

func UploadPptFile(c *gin.Context) {
	tokenstr := c.PostForm("token")
	pptid := c.PostForm("ppt_id")
	if tokenstr == "" || pptid == "" {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	if tokenstr == "" {
		c.JSON(200, gin.H{
			"message": "请登录",
		})
		return
	}

	userId, err := method.GetTokenId(tokenstr)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "token错误",
		})
		return
	}
	var pptList sql.PptList
	method.Db.First(&pptList, pptid)
	if userId != pptList.User {
		c.JSON(200, gin.H{
			"message": "没有权限",
		})
		return
	}
	file, _ := c.MultipartForm()

	files := file.File["files"]
	if len(files) == 0 {
		c.JSON(200, gin.H{
			"message": "请上传文件",
		})
		return
	}
	fileList := []pptFilesLiats{}
	for _, f := range files {
		refileName := f.Filename
		if refileName == "" {
			c.JSON(200, gin.H{
				"message": "请上传文件",
			})
			return
		}
		ext := filepath.Ext(refileName)
		randName := uuid.New().String()
		fileName := randName + ext
		dst := "./ppts/" + fileName
		err := c.SaveUploadedFile(f, dst)
		if err != nil {
			c.JSON(200, gin.H{
				"message": "上传失败",
			})
			return
		}
		fileList = append(fileList, pptFilesLiats{
			Path:     dst,
			FileName: refileName,
			Size:     method.FormatFileSize(f.Size),
			Time:     time.Now().Unix(),
			Type:     ext,
		})

	}

	pptId, _ := strconv.ParseInt(pptid, 10, 64)
	// 将fileList这个数组转换为字符串
	fileListStr, _ := json.Marshal(fileList)
	data := &sql.PptFiles{
		PptId:   pptId,
		FileUrl: string(fileListStr),
		Time:    time.Now().Unix(),
	}
	// 检查数据是否已经存在
	method.Db.Where("ppt_id = ?", pptId).FirstOrInit(data)
	if data.ID == 0 {
		method.Db.Create(data)
	} else {

		// 取出旧的数据中的file_url
		var oldData sql.PptFiles
		method.Db.Model(&sql.PptFiles{}).Find(&oldData, data.ID)
		var fileList []pptFilesLiats
		json.Unmarshal([]byte(oldData.FileUrl), &fileList)
		println("oldData:", oldData.FileUrl)
		for _, file := range fileList {
			// 删除旧的文件
			os.Remove(file.Path)
		}
		method.Db.Model(&sql.PptFiles{}).Where("id = ?", data.ID).Update("file_url", string(fileListStr))

	}

	method.Db.Model(&sql.PptList{}).Find(&pptList, pptid).Update("file_id", data.ID)
	c.JSON(200, gin.H{
		"message": "success",
	})
}

func DelPpt(c *gin.Context) {
	type ppt struct {
		Token string `json:"token"`
		PptId int64  `json:"ppt_id"`
	}
	var pptData ppt
	err := method.ParseJSON(c, &pptData)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	if pptData.Token == "" {
		c.JSON(200, gin.H{
			"message": "请登录",
		})
		return
	}
	if pptData.PptId == 0 {
		c.JSON(200, gin.H{
			"message": "请输入参数",
		})
		return
	}
	userId, err := method.GetTokenId(pptData.Token)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "token错误",
		})
		return
	}

	err = method.Db.Model(&sql.PptList{}).Where("id = ? AND user = ?", pptData.PptId, userId).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		c.JSON(200, gin.H{
			"message": "没有权限",
		})
		return
	}

	/*
		if userId == int64(0) {
			var pptList sql.PptList
			method.Db.Where("id = ?", pptData.PptId).First(&pptList)
			method.Db.Delete(&sql.PptList{}, pptData.PptId)// 先删除pptList
			if pptList.FileId != 0 { // 已经上传文件
				var fileInfo sql.PptFiles
				method.Db.Where("id = ?", pptList.FileId).First(&fileInfo)
				if fileInfo.ID != 0 { // 下载记录存在
					method.Db.Delete(&sql.DownloadList{},"file_id = ?", fileInfo.ID)
				}
				method.Db.Where("id = ?", pptList.FileId).Delete(&sql.PptFiles{})// 删除文件
			}
		}else {

		}
	*/

	var pptList sql.PptList
	method.Db.Where("id = ?", pptData.PptId).First(&pptList)
	method.Db.Delete(&sql.PptList{}, pptData.PptId)
	if pptList.FileId != 0 {
		var fileInfo sql.PptFiles
		method.Db.Where("id = ?", pptList.FileId).First(&fileInfo)
		err = method.Db.Delete(&sql.DownloadList{}, "file_id = ?", fileInfo.ID).Error
		if err == nil {
			method.Db.Delete(&sql.DownloadList{}, "file_id = ?", fileInfo.ID)
		}
		method.Db.Where("id = ?", pptList.FileId).Delete(&sql.PptFiles{})
	}

	c.JSON(200, gin.H{
		"message": "success",
	})
}

func CreatePptDownloadKey(c *gin.Context) {
	type ppt struct {
		PptId    int64  `json:"ppt_id"`
		Token    string `json:"token"`
		FilesKey int64  `json:"files_key"`
	}

	var pptData ppt
	err := method.ParseJSON(c, &pptData)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	if pptData.Token == "" {
		c.JSON(200, gin.H{
			"message": "请登录",
		})
		return
	}
	userId, err := method.GetTokenId(pptData.Token)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "token错误",
		})
		return
	}
	var pptlist sql.PptList
	method.Db.Where("id = ?", pptData.PptId).First(&pptlist)
	var pptfile sql.PptFiles
	method.Db.Where("id = ?", pptlist.FileId).First(&pptfile)
	var filelist []pptFilesLiats
	err = json.Unmarshal([]byte(pptfile.FileUrl), &filelist)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "文件解析失败",
		})
		return
	}
	if len(filelist)-int(pptData.FilesKey) < 0 {
		c.JSON(200, gin.H{
			"message": "文件不存在",
		})
		return
	}
	timeNow := time.Now().Unix()
	data := &sql.DownloadList{
		UserId:      userId,
		FilesKey:    pptData.FilesKey,
		FileId:      int64(pptfile.ID),
		Time:        timeNow,
		DownloadNum: 0,
		StopTime:    timeNow + 60*20,
	}
	method.Db.Create(&data)
	timeNowStr := strconv.FormatInt(timeNow, 10)
	c.JSON(200, gin.H{
		"message": "success",
		"id":      timeNowStr,
	})
}
func DownloadPpt(c *gin.Context) {
	id := c.Param("id")
	if id == "" {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}

	var downlist sql.DownloadList
	err := method.Db.Where("time = ?", id).First(&downlist).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		c.JSON(200, gin.H{
			"message": "文件不存在",
		})
		return
	}
	if time.Now().Unix() > downlist.StopTime {
		method.Db.Delete(&sql.DownloadList{}, "time = ?", id)
		c.JSON(200, gin.H{
			"message": "文件已过期",
		})
		return
	}
	if downlist.DownloadNum >= method.Config.Server.PptDownloadNum {
		c.JSON(200, gin.H{
			"message": "文件下载次数已用完",
		})
		return
	}
	method.Db.Model(&sql.DownloadList{}).Where("time = ?", id).Update("download_num", downlist.DownloadNum+1)
	var pptfile sql.PptFiles
	method.Db.Where("id = ?", downlist.FileId).First(&pptfile)
	var pptlist sql.PptList
	method.Db.Where("id = ?", pptfile.PptId).First(&pptlist).Update("download_num", pptlist.DownloadNum+1)
	var FileList []pptFilesLiats
	err = json.Unmarshal([]byte(pptfile.FileUrl), &FileList)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "文件解析失败",
		})
		return
	}
	if len(FileList)-int(downlist.FilesKey) < 0 {
		c.JSON(200, gin.H{
			"message": "文件不存在",
		})
		return
	}
	log.Println(downlist.FilesKey, FileList)
	c.File(FileList[int(downlist.FilesKey)].Path)

}

func GetPptList(c *gin.Context) {
	page := c.Param("page")
	pageint, err := strconv.Atoi(page)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	offset := (pageint - 1) * method.Config.Server.PptPageShowNum
	var list []sql.PptList
	err = method.Db.Order("id desc").Offset(offset).Limit(method.Config.Server.PptPageShowNum).Find(&list).Error
	if err != nil {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	type reData struct {
		Title       string `json:"title"`
		Img         string `json:"img"`
		UserName    string `json:"user_name"`
		UserImg     string `json:"user_img"`
		Time        int64  `json:"time"`
		ShowNum     int64  `json:"show_num"`
		DownloadNum int64  `json:"download_num"`
		Id          int64  `json:"id"`
		HomeInfo    string `json:"home_info"`
	}
	var data []reData
	for i := 0; i < len(list); i++ {
		var user sql.User
		method.Db.First(&user, list[i].User)
		data = append(data, reData{
			Title:       list[i].Title,
			Img:         method.Config.Server.ServerName + "api/pptImg/" + strconv.FormatInt(int64(list[i].ID), 10),
			UserName:    user.Name,
			UserImg:     method.Config.Server.ServerName + "api/userImg/" + strconv.FormatInt(int64(list[i].User), 10),
			Time:        list[i].Time,
			ShowNum:     list[i].ShowNum,
			DownloadNum: list[i].DownloadNum,
			Id:          int64(list[i].ID),
			HomeInfo:    list[i].HomeInfo,
		})
	}
	c.JSON(200, gin.H{
		"message": "success",
		"data":    data,
	})
}

func UploadPptIcon(c *gin.Context) {
	token := c.PostForm("token")
	ppt_id := c.PostForm("ppt_id")
	if token == "" || ppt_id == "" {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	userId, err := method.GetTokenId(token)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "token错误",
		})
		return
	}
	var pptList sql.PptList
	method.Db.First(&pptList, ppt_id)
	if userId != pptList.User {
		c.JSON(200, gin.H{
			"message": "没有权限",
		})
		return
	}
	file, err := c.FormFile("file")
	if err != nil {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	if file.Size > 1024*1024*2 {
		c.JSON(200, gin.H{
			"message": "文件过大",
		})
		return
	}
	var imgUrl string
	if file.Filename != "" {
		if !strings.HasSuffix(file.Filename, ".jpg") && !strings.HasSuffix(file.Filename, ".png") {
			c.JSON(200, gin.H{
				"message": "文件格式错误",
			})
			return
		}
		ext := filepath.Ext(file.Filename)
		randName := uuid.New().String()
		fileName := randName + ext
		dst := "./pptImg/" + fileName
		err = c.SaveUploadedFile(file, dst)
		if err != nil {
			c.JSON(200, gin.H{
				"message": "保存失败",
			})
			return
		}
		method.Db.Model(&sql.PptList{}).Where("id = ?", ppt_id).Update("img", dst)
		imgUrl = method.Config.Server.ServerName + "api/pptImg/" + ppt_id
	}
	c.JSON(200, gin.H{
		"message": "success",
		"img":     imgUrl,
	})
}

func PptImg(c *gin.Context) {
	id := c.Param("id")
	if id == "" {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	var pptList sql.PptList
	err := method.Db.Where("id = ?", id).First(&pptList).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		c.JSON(200, gin.H{
			"message": "文件不存在",
		})
		return
	}
	dirr := ""
	dirr = pptList.Img
	if pptList.Img == "" {
		dir, err := method.PptImg(300, 150, pptList.Title)
		if err != nil {
			c.JSON(200, gin.H{
				"message": "生成图片失败",
			})
			return
		}
		method.Db.Model(&sql.PptList{}).Where("id = ?", id).Update("img", dir)
		dirr = dir
	}
	c.File(dirr)
}

func GetPptReview(c *gin.Context) {
	type ppt struct {
		Token string `json:"token"`
		PptId int64  `json:"ppt_id"`
	}
	var pptData ppt
	err := method.ParseJSON(c, &pptData)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}

	if pptData.Token == "" || pptData.PptId == 0 {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	var pptdata sql.PptList
	err = method.Db.Where("id = ?", pptData.PptId).First(&pptdata).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		c.JSON(200, gin.H{
			"message": "文件不存在",
		})
		return
	}
	if pptdata.Review == "" {
		c.JSON(200, gin.H{
			"message": "没有评论",
		})
		return
	}
	// os读取文件
	file, err := os.ReadFile(pptdata.Review)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "文件不存在",
		})
		return
	}

	var afterreview []MainStruct

	err = json.Unmarshal([]byte(string(file)), &afterreview)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "评论解析错误",
		})
		return
	}
	type User struct {
		Name string `json:"name"`
		Img  string `json:"img"`
	}
	type RrMain struct {
		User  User     `json:"user"`
		Main  string   `json:"main"`
		Files []string `json:"files"`
		Time  int64    `json:"time"`
	}
	type Rmain struct {
		User   string   `json:"user"`
		Main   string   `json:"main"`
		Files  []string `json:"files"`
		Time   int64    `json:"time"`
		Review []RrMain `json:"review"`
	}
	//main := []Rmain{}
	//user := []User{}
	//rrmain := []RrMain{}
	//for i := 0; i < len(afterreview); i++ {
	//	var userI sql.User
	//	method.Db.Where("id = ?", afterreview[i].UID).First(&userI)
	//}

	c.JSON(200, gin.H{
		"message": "success",
		"main":    afterreview,
	})
}

func PptInfo(c *gin.Context) {
	type ppt struct {
		PptId int64 `json:"ppt_id"`
	}
	var pptData ppt
	err := method.ParseJSON(c, &pptData)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}

	var pptdata sql.PptList
	err = method.Db.Where("id = ?", pptData.PptId).First(&pptdata).Error
	if errors.Is(err, gorm.ErrRecordNotFound) {
		c.JSON(200, gin.H{
			"message": "ppt不存在",
		})
		return
	}

	method.Db.Model(&sql.PptList{}).Where("id = ?", pptData.PptId).Update("show_num", gorm.Expr("show_num + ?", 1))

	type fileinfo struct {
		FileName string `json:"file_name"`
		Size     string `json:"size"`
		Time     int64  `json:"time"`
		Type     string `json:"type"`
		Key      int64  `json:"key"`
	}
	var fileInfo []fileinfo
	var pptFiles sql.PptFiles
	err = method.Db.Where("ppt_id = ?", pptData.PptId).First(&pptFiles).Error
	if err == nil {
		//fileInfo = []fileinfo{}
		// 将pptFiles.FileUrl 转换为 json
		var fileUrl []pptFilesLiats
		err = json.Unmarshal([]byte(pptFiles.FileUrl), &fileUrl)
		if err != nil {
			c.JSON(200, gin.H{
				"message": "文件解析错误",
			})
			return
		}
		for i := 0; i < len(fileUrl); i++ {
			fileInfo = append(fileInfo, fileinfo{
				FileName: fileUrl[i].FileName,
				Size:     fileUrl[i].Size,
				Time:     fileUrl[i].Time,
				Type:     fileUrl[i].Type,
				Key:      int64(i),
			})
		}
	}

	var user sql.User
	method.Db.Where("id = ?", pptdata.User).First(&user)

	userData := struct {
		UserName string `json:"user_name"`
		UserId   int64  `json:"user_id"`
		UserInfo string `json:"user_info"`
	}{
		UserName: user.Name,
		UserId:   int64(user.ID),
		UserInfo: user.Info,
	}

	var data = struct {
		Title       string `json:"title"`
		Img         string `json:"img"`
		Time        int64  `json:"time"`
		DownloadNum int64  `json:"download_num"`
		ShowNum     int64  `json:"show_num"`
		Instruction string `json:"instruction"`
	}{
		Title:       pptdata.Title,
		Img:         method.Config.Server.ServerName + "api/pptImg/" + strconv.FormatInt(int64(pptdata.ID), 10),
		Time:        pptdata.Time,
		DownloadNum: pptdata.DownloadNum,
		ShowNum:     pptdata.ShowNum + 1,
		Instruction: pptdata.Instruction,
	}

	c.JSON(200, gin.H{
		"message": "success",
		"data":    data,
		"files":   fileInfo,
		"user":    userData,
	})

}

func GetUserPptList(c *gin.Context) {
	type ppt struct {
		Token string `json:"token"`
		Uid   int64  `json:"uid"`
		Page  int64  `json:"page"`
	}
	var pptData ppt
	err := method.ParseJSON(c, &pptData)
	if err != nil {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}
	if pptData.Token == "" {
		c.JSON(200, gin.H{
			"message": "请登录",
		})
		return
	}

	if pptData.Uid == 0 {
		c.JSON(200, gin.H{
			"message": "参数错误",
		})
		return
	}

	var pptList []sql.PptList
	// 请你根据page进行分页查询
	offset := (pptData.Page - 1) * int64(method.Config.Server.PptPageShowNum)
	err = method.Db.Where("user = ?", pptData.Uid).Order("id desc").Offset(int(offset)).Limit(method.Config.Server.PptPageShowNum).Find(&pptList).Error
	if err != nil {
		c.JSON(200, gin.H{
			"message": "ppt不存在",
		})
		return
	}
	type reData struct {
		Title    string `json:"title"`
		HomeInfo string `json:"home_info"`
		Time     int64  `json:"time"`
		ShowNum  int64  `json:"show_num"`
		Id       int64  `json:"id"`
	}
	var data []reData
	for i := 0; i < len(pptList); i++ {
		data = append(data, reData{
			Title:    pptList[i].Title,
			HomeInfo: pptList[i].HomeInfo,
			Time:     pptList[i].Time,
			ShowNum:  pptList[i].ShowNum,
			Id:       int64(pptList[i].ID),
		})
	}
	c.JSON(200, gin.H{
		"message": "success",
		"data":    data,
	})

}
